import Watcher from "./observe/watcher";
import { createElementVNode, createTextVNode } from "./vdom/index";

/*
 * @Author: zzd993
 * @Date: 2023-02-10 21:11:49
 * @LastEditors: zzd993
 * @LastEditTime: 2023-02-13 16:24:34
 * @FilePath: \手写vue2源码\src\lifecycle.js
 * Copyright (c) 2023 by ZZD, All Rights Reserved. 
 */

function createElm(vnode) {
    let { tag, data, children, text } = vnode
    if(typeof tag === 'string') {  // 标签
        vnode.el = document.createElement(tag)  // 这里将真实节点和虚拟节点对应起来，后续如果修改了
        
        patchProps(vnode.el, data)
        children.forEach(child => {
            vnode.el.appendChild(createElm(child))
        });
    } else {
        vnode.el = document.createTextNode(text)
    }
    return vnode.el
}

function patchProps(el, props) {
    for (let key in props) {
        if(key === 'style') { // style {color: 'red'}
            for(let styleName in props.style) {
                el.style[styleName] = props.style[styleName]
            }
        } else {
            el.setAttribute(key, props[key])
        }
    }
}

function patch(oldVNode, vnode) {
    // 判断是不是初渲染流程
    const isRealElement = oldVNode.nodeType // 是1的话就是真实元素
    if(isRealElement) {
        const elm = oldVNode  // 获取真实元素
        const parentElm = elm.parentNode  // 拿到父元素
        let newElm = createElm(vnode)
        parentElm.insertBefore(newElm, elm.nextSibling)
        parentElm.removeChild(elm)  // 删除老节点

        return newElm
    } else {
        //  diff算法
    }
}

export function initLifeCycle(Vue) {
    Vue.prototype._update = function(vnode) {
        // console.log(vnode);
        const vm = this
        const el = vm.$el
        // 既有初始化的功能，又有更新的功能
        vm.$el = patch(el, vnode)
    }

    // _c('div',{},...children)
    Vue.prototype._c = function() {
        // console.log('ok');
        return createElementVNode(this,...arguments)
    }
    // _v(text)
    Vue.prototype._v = function() {
        // console.log('ok');
        return createTextVNode(this,...arguments)
    }
    Vue.prototype._s = function(value) {
        if(typeof value !== 'object') return value
        return JSON.stringify(value)
    }
    Vue.prototype._render = function() {
        return this.$options.render.call(this)   // 通过ast语法转义后生成的render方法
    }
}
export function mountComponent(vm, el) {
    vm.$el = el
    // 1. 调用render方法产生虚拟节点 虚拟DOM

    const updateComponent = () => {
        vm._update(vm._render())
    }
    // 依赖收集
    new Watcher(vm, updateComponent, true)  // true标识是一个渲染watcher

}

export function callHook(vm, hook) {
    const handlers = vm.$options[hook]
    if(handlers) {
        handlers.forEach(handler => handler.call(vm))
    }
}